Iflow

Librerías

library(leaflet)
library(tidyverse)
library(readxl)
library(lubridate)
library(kableExtra)
library(GGally)
library(corrplot)
library(ggplot2)
library(dplyr)
library(gridExtra)
library(osmdata)
library(sf)
library(ggmap)
library(MASS)

Cargar Datos

df <- read_excel("iFlowDatos.xlsx") 
df
# A tibble: 27,484 × 16
   iddomicilioorden direccion      localidad InicioHorario1 FinHorario1 latitud
              <dbl> <chr>          <chr>              <dbl>       <dbl>   <dbl>
 1            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 2            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 3            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 4            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 5            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 6            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 7            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 8            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 9            74958 M PEDRAZA 2370 CAPITAL              901        1401   -34.6
10            74958 M PEDRAZA 2370 CAPITAL              901        1401   -34.6
# ℹ 27,474 more rows
# ℹ 10 more variables: longitud <dbl>, cliente <dbl>, mes <dbl>, Bultos <dbl>,
#   Peso <dbl>, Unidades <dbl>, InicioVisitaPlanificado <chr>,
#   FinVisitaPlanificado <chr>, InicioVisitaReal <chr>, FinVisitaReal <chr>

Limpieza de los Datos

df_clean <- df %>% 
  filter(latitud<(-34),longitud<(-58)) %>% 
  mutate(inicio = parse_date_time(InicioVisitaReal, orders = c("ymd HMS", "ymd_HMS", "dmy HMS"), tz = Sys.timezone(), quiet = TRUE)) %>% na.omit()%>%
  mutate(cliente = as.factor(cliente))

names(df_clean) <- tolower(names(df_clean))
df_clean
# A tibble: 27,382 × 17
   iddomicilioorden direccion      localidad iniciohorario1 finhorario1 latitud
              <dbl> <chr>          <chr>              <dbl>       <dbl>   <dbl>
 1            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 2            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 3            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 4            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 5            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 6            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 7            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 8            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 9            74958 M PEDRAZA 2370 CAPITAL              901        1401   -34.6
10            74958 M PEDRAZA 2370 CAPITAL              901        1401   -34.6
# ℹ 27,372 more rows
# ℹ 11 more variables: longitud <dbl>, cliente <fct>, mes <dbl>, bultos <dbl>,
#   peso <dbl>, unidades <dbl>, iniciovisitaplanificado <chr>,
#   finvisitaplanificado <chr>, iniciovisitareal <chr>, finvisitareal <chr>,
#   inicio <dttm>
dim(df_clean)
[1] 27382    17

Análisis de Datos Básico

summary(df_clean)
 iddomicilioorden  direccion          localidad         iniciohorario1
 Min.   : 74956   Length:27382       Length:27382       Min.   :  0   
 1st Qu.: 77460   Class :character   Class :character   1st Qu.:901   
 Median : 82348   Mode  :character   Mode  :character   Median :901   
 Mean   :101622                                         Mean   :901   
 3rd Qu.:121664                                         3rd Qu.:901   
 Max.   :183277                                         Max.   :901   
  finhorario1      latitud          longitud      cliente         mes       
 Min.   :1400   Min.   :-34.85   Min.   :-58.73   20:16510   Min.   :5.000  
 1st Qu.:1401   1st Qu.:-34.62   1st Qu.:-58.48   70:10872   1st Qu.:5.000  
 Median :1401   Median :-34.60   Median :-58.44              Median :6.000  
 Mean   :1401   Mean   :-34.60   Mean   :-58.44              Mean   :6.021  
 3rd Qu.:1401   3rd Qu.:-34.58   3rd Qu.:-58.40              3rd Qu.:7.000  
 Max.   :2359   Max.   :-34.39   Max.   :-58.15              Max.   :7.000  
     bultos             peso            unidades       iniciovisitaplanificado
 Min.   :  0.100   Min.   :   0.00   Min.   :   1.00   Length:27382           
 1st Qu.:  2.000   1st Qu.:  13.00   1st Qu.:   2.00   Class :character       
 Median :  3.000   Median :  20.94   Median :   6.00   Mode  :character       
 Mean   :  5.692   Mean   :  40.95   Mean   :  28.37                          
 3rd Qu.:  6.000   3rd Qu.:  39.00   3rd Qu.:  40.00                          
 Max.   :360.000   Max.   :2475.00   Max.   :2203.00                          
 finvisitaplanificado iniciovisitareal   finvisitareal     
 Length:27382         Length:27382       Length:27382      
 Class :character     Class :character   Class :character  
 Mode  :character     Mode  :character   Mode  :character  
                                                           
                                                           
                                                           
     inicio                      
 Min.   :2024-05-03 07:17:51.00  
 1st Qu.:2024-05-24 15:38:00.00  
 Median :2024-06-18 10:34:53.00  
 Mean   :2024-06-17 22:15:43.75  
 3rd Qu.:2024-07-11 11:21:32.00  
 Max.   :2024-08-06 16:57:00.00  

Distintas Variables

colnames(df_clean)
 [1] "iddomicilioorden"        "direccion"              
 [3] "localidad"               "iniciohorario1"         
 [5] "finhorario1"             "latitud"                
 [7] "longitud"                "cliente"                
 [9] "mes"                     "bultos"                 
[11] "peso"                    "unidades"               
[13] "iniciovisitaplanificado" "finvisitaplanificado"   
[15] "iniciovisitareal"        "finvisitareal"          
[17] "inicio"                 
sapply(df_clean, class)
$iddomicilioorden
[1] "numeric"

$direccion
[1] "character"

$localidad
[1] "character"

$iniciohorario1
[1] "numeric"

$finhorario1
[1] "numeric"

$latitud
[1] "numeric"

$longitud
[1] "numeric"

$cliente
[1] "factor"

$mes
[1] "numeric"

$bultos
[1] "numeric"

$peso
[1] "numeric"

$unidades
[1] "numeric"

$iniciovisitaplanificado
[1] "character"

$finvisitaplanificado
[1] "character"

$iniciovisitareal
[1] "character"

$finvisitareal
[1] "character"

$inicio
[1] "POSIXct" "POSIXt" 

Cambiar las variables, para que las que tengan que estar en formato fecha, lo estén

df_clean$iniciovisitaplanificado <- as.POSIXct(df_clean$iniciovisitaplanificado, format = "%Y-%m-%d %H:%M:%OS", tz = "UTC")
df_clean$finvisitaplanificado <- as.POSIXct(df_clean$finvisitaplanificado, format = "%Y-%m-%d %H:%M:%OS", tz = "UTC")
df_clean$iniciovisitareal <- as.POSIXct(df_clean$iniciovisitareal, format = "%Y-%m-%d %H:%M:%OS", tz = "UTC")
df_clean$finvisitareal <- as.POSIXct(df_clean$finvisitareal, format = "%Y-%m-%d %H:%M:%OS", tz = "UTC")

df_clean
# A tibble: 27,382 × 17
   iddomicilioorden direccion      localidad iniciohorario1 finhorario1 latitud
              <dbl> <chr>          <chr>              <dbl>       <dbl>   <dbl>
 1            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 2            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 3            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 4            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 5            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 6            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 7            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 8            74956 VIDAL 2044     CAPITAL              901        1401   -34.6
 9            74958 M PEDRAZA 2370 CAPITAL              901        1401   -34.6
10            74958 M PEDRAZA 2370 CAPITAL              901        1401   -34.6
# ℹ 27,372 more rows
# ℹ 11 more variables: longitud <dbl>, cliente <fct>, mes <dbl>, bultos <dbl>,
#   peso <dbl>, unidades <dbl>, iniciovisitaplanificado <dttm>,
#   finvisitaplanificado <dttm>, iniciovisitareal <dttm>, finvisitareal <dttm>,
#   inicio <dttm>
colnames(df_clean)
 [1] "iddomicilioorden"        "direccion"              
 [3] "localidad"               "iniciohorario1"         
 [5] "finhorario1"             "latitud"                
 [7] "longitud"                "cliente"                
 [9] "mes"                     "bultos"                 
[11] "peso"                    "unidades"               
[13] "iniciovisitaplanificado" "finvisitaplanificado"   
[15] "iniciovisitareal"        "finvisitareal"          
[17] "inicio"                 
sapply(df_clean, class)
$iddomicilioorden
[1] "numeric"

$direccion
[1] "character"

$localidad
[1] "character"

$iniciohorario1
[1] "numeric"

$finhorario1
[1] "numeric"

$latitud
[1] "numeric"

$longitud
[1] "numeric"

$cliente
[1] "factor"

$mes
[1] "numeric"

$bultos
[1] "numeric"

$peso
[1] "numeric"

$unidades
[1] "numeric"

$iniciovisitaplanificado
[1] "POSIXct" "POSIXt" 

$finvisitaplanificado
[1] "POSIXct" "POSIXt" 

$iniciovisitareal
[1] "POSIXct" "POSIXt" 

$finvisitareal
[1] "POSIXct" "POSIXt" 

$inicio
[1] "POSIXct" "POSIXt" 

Análisis

df_clean <- df_clean %>%
  mutate(TiempoEntrega = finvisitareal - iniciovisitareal)

Cantidad de entregas por localidad

df_counts <- df_clean %>%
  group_by(localidad) %>%
  summarise(conteo = n())%>%
  arrange(desc(conteo))%>%
  head(5)

ggplot(df_counts, aes(x = localidad, y =conteo)) +
  geom_bar(stat = "identity") 

Calculamos el tiempo promedio de demora en la salida, y en la llegada

calcular_tiempo_formateado <- function(inicio, fin) {
  # Calcula la diferencia en minutos con decimales
  tiempo_minutos_dec <- as.numeric(difftime(fin, inicio, units = "mins"))
 
  tiempo_minutos <- floor(tiempo_minutos_dec)
  # Retorna el valor numérico
  return(tiempo_minutos)
}

df_clean <- df_clean %>%
  mutate(DemoraSalida = calcular_tiempo_formateado(iniciovisitaplanificado, iniciovisitareal))%>%
  mutate(DemoraLlegada = calcular_tiempo_formateado(finvisitaplanificado, finvisitareal))

promedio_demora_salida <- mean(df_clean$DemoraSalida,na.rm = TRUE)
promedio_demora_salida
[1] 133.482
promedio_demora_llegada <- mean(df_clean$DemoraLlegada,na.rm=TRUE)
promedio_demora_llegada
[1] 139.4571

Con lo calculado arriba, sacamos el tiempo promedio de demora en la salida y llegada, en las distintas localidades y graficamos

df_demora_por_localidad <- df_clean%>%
  group_by(localidad) %>%
  summarise(demora_salida_localidad=mean(DemoraSalida,na.rm = T),demora_llegada_localidad=mean(DemoraLlegada,na.rm = T)) %>%
  arrange(demora_salida_localidad) %>%
  filter(demora_salida_localidad < 3000) %>%
  mutate(localidad = factor(localidad, levels = localidad))
  
  
ggplot(df_demora_por_localidad,aes(x=localidad,y=demora_salida_localidad)) +
  geom_bar(stat="identity") +
  labs(title = "Demora de Salida por Localidad",
       x = "Localidad",
       y = "Demora de Salida (promedio)") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(df_demora_por_localidad,aes(x=localidad,y=demora_llegada_localidad))+
  geom_bar(stat="identity")+
  labs(title = "Demora de llegada por Localidad",
       x = "Localidad",
       y = "Demora de Llegada (promedio)") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Ahora calculamos la demora promedio por cliente

demora_promedio_por_cliente <- df_clean%>%
  group_by(cliente) %>%
  summarise(demora_salida_cliente=mean(DemoraSalida,na.rm=T),demora_llegada_cliente=mean(DemoraLlegada,na.rm=T))

demora_melt <- reshape2::melt(demora_promedio_por_cliente, id.vars = 'cliente')

# Crear el gráfico con ggplot2
ggplot(demora_melt, aes(x = factor(cliente), y = value, fill = variable)) + 
  geom_bar(stat = 'identity', position = 'dodge') + 
  labs(x = 'Cliente', y = 'Demora', fill = 'Tipo de demora') + 
  scale_fill_manual(
    values = c("demora_salida_cliente" = "#FF6347", "demora_llegada_cliente" = "#20B2AA"),
    labels = c("demora_salida_cliente" = "Demora de Salida por Cliente", 
               "demora_llegada_cliente" = "Demora de Llegada por Cliente")
  ) + 
  theme_minimal()

Distribución de las entregas en un mapa

library(dplyr)
library(sf)
library(plotly)

Attaching package: 'plotly'
The following object is masked from 'package:MASS':

    select
The following object is masked from 'package:ggmap':

    wind
The following object is masked from 'package:ggplot2':

    last_plot
The following object is masked from 'package:stats':

    filter
The following object is masked from 'package:graphics':

    layout
Sys.setenv("MAPBOX_TOKEN" = "pk.eyJ1IjoiYWd1c3Rpbm9ydWUiLCJhIjoiY20yamR1dmlhMDRnMjJscHgxZTk4a3Z1OSJ9.3XpQh1Kfpitza34209j9vA")

df.sf <- df %>%
  filter(!is.na(longitud) & !is.na(latitud)) %>%
  filter(longitud < 0) %>%
  filter(latitud < -34.0) %>%
  st_as_sf(coords = c("longitud", "latitud"), crs = 4326)

coords <- st_coordinates(df.sf)

plot_ly() %>%
  add_trace(
    type = 'scattermapbox',
    mode = 'markers',
    lon = coords[, 1],
    lat = coords[, 2],  
    marker = list(size = 8, color = 'blue')  
  ) %>%
  layout(
    mapbox = list(
      style = 'streets', 
      zoom = 8,  
      center = list(lon = mean(coords[, 1]), lat = mean(coords[, 2]))  
    ),
    showlegend = FALSE  
  ) %>%
  config(mapboxAccessToken = Sys.getenv("MAPBOX_TOKEN")) 

Distribucion de las entregas de los distintos clientes

library(dplyr)
library(sf)
library(plotly)

Sys.setenv("MAPBOX_TOKEN" = "pk.eyJ1IjoiYWd1c3Rpbm9ydWUiLCJhIjoiY20yamR1dmlhMDRnMjJscHgxZTk4a3Z1OSJ9.3XpQh1Kfpitza34209j9vA")

df.sf <- df %>%
  filter(!is.na(longitud) & !is.na(latitud)) %>%
  filter(longitud < 0) %>%
  filter(latitud < -34.0) %>%
  st_as_sf(coords = c("longitud", "latitud"), crs = 4326)

# Extraer las coordenadas
coords <- st_coordinates(df.sf)

# Asignar etiquetas para la leyenda
df.sf$label <- case_when(
  df.sf$cliente == 20 ~ 'Cliente 20',  # Etiqueta para cliente 20
  df.sf$cliente == 70 ~ 'Cliente 70',  # Etiqueta para cliente 70
  TRUE ~ 'Otros Clientes'  # Otros clientes
)

# Asignar colores basados en la etiqueta
df.sf$color <- case_when(
  df.sf$cliente == 20 ~ '#FF6347',  
  df.sf$cliente == 70 ~ '#20B2AA',  
  TRUE ~ 'black'  
)

# Crear el gráfico con leyenda y colores personalizados
plot_ly() %>%
  add_trace(
    type = 'scattermapbox',
    mode = 'markers',
    lon = coords[, 1],  
    lat = coords[, 2],  
    text = df.sf$cliente,  
    marker = list(
      size = 8,
      color = df.sf$color  
    ),
    showlegend = TRUE,
    name = df.sf$label  
  ) %>%
  layout(
    mapbox = list(
      style = 'streets',
      zoom = 8,  
      center = list(lon = mean(coords[, 1]), lat = mean(coords[, 2]))  
    ),
    showlegend = TRUE  
  ) %>%
  config(mapboxAccessToken = Sys.getenv("MAPBOX_TOKEN"))

Peso por unidad

peso_por_unidad <- function(peso, unidades) {
  if (unidades == 0) {
    return(NA)  
  } else {
    return(peso / unidades) 
  }
}

df$peso_por_unidad <- mapply(peso_por_unidad, df$Peso, df$Unidades)

head(df[c("Peso", "Unidades", "peso_por_unidad")])
# A tibble: 6 × 3
   Peso Unidades peso_por_unidad
  <dbl>    <dbl>           <dbl>
1  24.9       30           0.830
2  26.3       38           0.691
3  24.9       32           0.778
4  14.0       28           0.501
5  14.4       31           0.464
6  13.8       25           0.551
ggplot(df, aes(x = peso_por_unidad)) +
  geom_histogram(binwidth = 0.6, fill = "blue", color = "black") +
  labs(title = "Distribución del Peso por Unidad", x = "Peso por Unidad", y = "Frecuencia")

Cantidad de entregas por mes

# Cargar librerías necesarias
library(ggplot2)
library(lubridate)

# Asegurarse de que la columna InicioVisitaPlanificado esté en formato Date
df$InicioVisitaPlanificado <- as.Date(df$InicioVisitaPlanificado, format = "%Y-%m-%d")

df_cantidad_de_entregas_por_dia<-df%>%
  group_by(InicioVisitaPlanificado)%>%
  summarise(n=n())%>%
  mutate(mes = month(InicioVisitaPlanificado))

ggplot(df_cantidad_de_entregas_por_dia, aes(x = InicioVisitaPlanificado, y = n, group = mes, color = as.factor(mes))) +
  geom_line(size = 0.8) +  # Líneas de cada mes
  geom_point(size = 1.5) +  # Añadir puntos en las líneas
  labs(title = "Cantidad de entregas a lo largo del tiempo por mes", 
       x = "Fecha de Inicio de Visita Planificado", 
       y = "Cantidad de entregas",
       color = "Mes") +  # Añadir etiqueta a la leyenda
  theme_minimal() +
  theme(panel.grid.major = element_line(color = "gray90"))  
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.

Cantidad de entregas por cliente en todos los meses

df$InicioVisitaPlanificado <- as.Date(df$InicioVisitaPlanificado, format = "%Y-%m-%d")
df$cliente<-as.character(df$cliente)
cantidad_entregas_por_cliente<-df%>%
  group_by(InicioVisitaPlanificado,cliente)%>%
  summarise(n=n())%>%
  mutate(mes = month(InicioVisitaPlanificado))
cantidad_entregas_por_cliente
# A tibble: 149 × 4
# Groups:   InicioVisitaPlanificado [77]
   InicioVisitaPlanificado cliente     n   mes
   <date>                  <chr>   <int> <dbl>
 1 2024-05-03              20        192     5
 2 2024-05-03              70        159     5
 3 2024-05-04              20        212     5
 4 2024-05-04              70        141     5
 5 2024-05-06              20        175     5
 6 2024-05-06              70        141     5
 7 2024-05-07              20        292     5
 8 2024-05-07              70        184     5
 9 2024-05-08              20        321     5
10 2024-05-08              70        164     5
# ℹ 139 more rows
ggplot(cantidad_entregas_por_cliente, aes(x =InicioVisitaPlanificado , y = n, color = cliente)) +
  geom_line(size = 1) +  
  geom_point(size = 2.5) +  
  labs(title = "Cantidad de productos entregados por cliente cada día", 
       x = "Fecha de Entrega", 
       y = "Cantidad de Productos Entregados",
       color = "Cliente") +  
  theme_minimal()

Cantidad de entregas por mes

df$mes <- as.factor(df$mes)


entregas_por_mes <- df %>%
  group_by(mes) %>%
  summarise(cantidad_entregas = n())

ggplot(entregas_por_mes, aes(x = mes, y = cantidad_entregas)) +
  geom_bar(stat = "identity", fill = "blue", color = "black") +
  labs(title = "Cantidad de Entregas por Mes", x = "Mes", y = "Cantidad de Entregas") +
  theme_minimal()

Distribución de entregas en los distintos días de la semana

library(plotly)
library(dplyr)
library(sf)
library(lubridate)

p <- plot_ly()

# Ordenar los días de la semana
dias_ordenados <- unique(df.sf$dia_semana)

for (dia in dias_ordenados) {
  df_dia <- df.sf[df.sf$dia_semana == dia, ]
  coords_dia <- st_coordinates(df_dia)
  
  p <- p %>%
    add_trace(
      type = 'scattermapbox',
      mode = 'markers',
      lon = coords_dia[, 1],
      lat = coords_dia[, 2],
      text = ~paste(df_dia$cliente, "<br>", df_dia$dia_semana),
      marker = list(size = 8),
      name = as.character(dia),
      visible = ifelse(dia == "Monday", TRUE, FALSE)  # Mostrar solo el Lunes inicialmente
    )
}

coords <- st_coordinates(df.sf)  
lon_center <- mean(coords[, 1], na.rm = TRUE)
lat_center <- mean(coords[, 2], na.rm = TRUE)

p <- p %>%
  layout(
    mapbox = list(
      style = 'streets',
      zoom = 8,
      center = list(lon = lon_center, lat = lat_center)  
    ),
    showlegend = TRUE,
    updatemenus = list(
      list(
        type = "buttons",
        direction = "down", 
        buttons = lapply(1:length(dias_ordenados), function(i) {
          list(
            method = "restyle",
            args = list("visible", lapply(1:length(dias_ordenados), function(j) j == i)),
            label = dias_ordenados[i]
          )
        }),
        pad = list(r = 10, t = 10),
        showactive = TRUE,
        x = 1.2, 
        xanchor = "right",
        y = 0.5,
        yanchor = "middle",
        bgcolor = "#F0F8FF",
        bordercolor = "#908090",
        borderwidth = 2,
        font = list(
          family = "Arial",
          size = 14,
          color = "#333333" 
        ),
        activecolor = "#1E90FF"
      )
    )
  ) %>%
  config(mapboxAccessToken = Sys.getenv("MAPBOX_TOKEN"))

p
library(plotly)
library(dplyr)
library(sf)
library(lubridate)

# Asegurarse de que la columna 'fecha' esté en formato Date (si no lo está ya)
df$InicioVisitaPlanificado <- as.Date(df$InicioVisitaPlanificado, format = "%Y-%m-%d")

# Agregar una columna con el día de la semana (1 = lunes, 7 = domingo)
df <- df %>%
  mutate(dia_semana = wday(InicioVisitaPlanificado, label = TRUE, abbr = FALSE))

# Filtrar y convertir los datos a objeto sf (para las coordenadas)
df.sf <- df %>%
  filter(!is.na(longitud) & !is.na(latitud)) %>%
  filter(longitud < 0) %>%
  filter(latitud < -34.0) %>%
  st_as_sf(coords = c("longitud", "latitud"), crs = 4326)

# Extraer las coordenadas
coords <- st_coordinates(df.sf)

# Crear un gráfico interactivo de puntos coloreados por día de la semana
plot_ly() %>%
  add_trace(
    type = 'scattermapbox',
    mode = 'markers',
    lon = coords[, 1],
    lat = coords[, 2],  
    text = ~paste(df.sf$cliente, "<br>", df.sf$dia_semana), 
    marker = list(
      size = 8
    ),
    color = ~df.sf$dia_semana,  
    colors = 'Set1'  
  ) %>%
  layout(
    mapbox = list(
      style = 'streets',
      zoom = 8,  
      center = list(lon = mean(coords[, 1]), lat = mean(coords[, 2])) 
    ),
    showlegend = TRUE  
  ) %>%
  config(mapboxAccessToken = Sys.getenv("MAPBOX_TOKEN"))

Cluster de Entregas por Localidad

coords <- df_clean %>% 
  select(latitud, longitud) %>%  # Ajustar si los nombres son diferentes
  na.omit()  # Eliminar filas con valores faltantes


clusters <- kmeans(coords, centers = 3)

df_clean$cluster <- as.factor(clusters$cluster)


ggplot(df_clean, aes(x = longitud, y = latitud, color = cluster)) +  # Ajustar nombres si es necesario
  geom_point() +
  labs(title = "Clusters de Entregas por Localidad") +
  theme_minimal()